package com.yuxl.admin.manager.auth.core.service;

import com.yuxl.admin.manager.auth.core.entity.AuthUser;
import com.yuxl.admin.manager.auth.core.entity.AuthRole;
import com.yuxl.admin.manager.auth.core.entity.AuthUserRole;
import com.yuxl.admin.manager.auth.core.repository.AuthUserRepository;
import com.yuxl.admin.manager.auth.core.repository.AuthUserRoleRepository;
import com.yuxl.admin.manager.auth.core.repository.AuthRoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;

@Slf4j
@Service
public class AuthUserService {

    private final AuthUserRepository userRepository;
    private final AuthUserRoleRepository userRoleRepository;
    private final AuthRoleRepository roleRepository;

    public AuthUserService(AuthUserRepository userRepository, AuthUserRoleRepository userRoleRepository, AuthRoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.userRoleRepository = userRoleRepository;
        this.roleRepository = roleRepository;
    }

    public Mono<AuthUser> findById(Long id) {
        return userRepository.findById(id);
    }

    public Flux<AuthUser> findAll(Integer page, Integer size) {
//        if (page != null && size != null) {
//            return userRepository.findAll()
//                    .skip((long) page * size)
//                    .take(size);
//        }
        return userRepository.findAll();
    }

    public Mono<AuthUser> findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    public Mono<AuthUser> createUser(AuthUser user) {
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }

    public Mono<AuthUser> updateUser(Long id, AuthUser user) {
        return userRepository.findById(id)
                .flatMap(existingUser -> {
                    existingUser.setUsername(user.getUsername());
                    existingUser.setPassword(user.getPassword());
                    existingUser.setUpdateTime(LocalDateTime.now());
                    return userRepository.save(existingUser);
                });
    }

    public Mono<Boolean> deleteUser(Long id) {
        return userRepository.deleteById(id).thenReturn(true);
    }

    public Mono<Boolean> assignRoleToUser(Long userId, Long roleId) {
        return userRoleRepository.save(new AuthUserRole(userId, roleId))
                .thenReturn(true)
                .onErrorResume(e -> Mono.just(false));
    }

    public Flux<AuthUser> findUsersByRoleId(Long roleId) {
        return userRoleRepository.findByRoleId(roleId)
                .flatMap(userRole -> userRepository.findById(userRole.getUserId()));
    }

    public Flux<AuthUser> searchUsers(String username, LocalDateTime startTime, LocalDateTime endTime, Integer page, Integer size) {
        log.debug("Searching users with params: username={}, startTime={}, endTime={}, page={}, size={}",
                     username, startTime, endTime, page, size);
        
        Flux<AuthUser> users;
        if (username != null && startTime != null && endTime != null) {
            users = userRepository.findByUsernameAndCreateTimeBetween(username, startTime, endTime);
        } else if (username != null) {
            users = userRepository.findByUsername(username).flux();
        } else if (startTime != null && endTime != null) {
            users = userRepository.findByCreateTimeBetween(startTime, endTime);
        } else {
            users = userRepository.findAll();
        }

        if (page != null && size != null) {
            users = users.skip((long) page * size).take(size);
        }

        return users
            .doOnNext(user -> log.debug("Found user: {}", user))
            .doOnComplete(() -> log.debug("User search completed"))
            .doOnError(e -> log.error("Error searching users", e));
    }

    public Mono<Long> countUsers(String username, LocalDateTime startTime, LocalDateTime endTime) {
        log.debug("Counting users: username={}, startTime={}, endTime={}", username, startTime, endTime);
        
        if (username != null && startTime != null && endTime != null) {
            return userRepository.findByUsernameAndCreateTimeBetween(username, startTime, endTime).count();
        } else if (username != null) {
            return userRepository.findByUsername(username).flatMap(user -> Mono.just(1L)).defaultIfEmpty(0L);
        } else if (startTime != null && endTime != null) {
            return userRepository.findByCreateTimeBetween(startTime, endTime).count();
        } else {
            return userRepository.count();
        }
    }

    public Flux<AuthRole> findRolesByUserId(Long userId) {
        return userRoleRepository.findByUserId(userId)
                .flatMap(userRole -> roleRepository.findById(userRole.getRoleId()));
    }
}
